﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using Microsoft.Windows.Controls.Ribbon;
using Puzzler.GUI.Exceptions;
using Puzzler.XML;

namespace Puzzler.GUI
{
    internal sealed class RibbonDelegates
    {
        public Action<String> ButtonDelegate { get; private set; }
        public Action<String> CheckedDelegate { get; private set; }
        public Action<String> UncheckedDelegate { get; private set; }
        public Action<String> SelectedDelegate { get; private set; }
        public Action<String> UnselectedDelegate { get; private set; }

        public RibbonDelegates(Action<string> buttonDelegate, Action<string> checkedDelegate, Action<string> uncheckedDelegate, Action<string> selectedDelegate, Action<string> unselectedDelegate)
        {
            ButtonDelegate = buttonDelegate;
            CheckedDelegate = checkedDelegate;
            UncheckedDelegate = uncheckedDelegate;
            SelectedDelegate = selectedDelegate;
            UnselectedDelegate = unselectedDelegate;
        }
    }

    internal static class RibbonBuilder
    {
        public static void ExtendRibbon(Ribbon ribbon, XRibbonExtension xRibbonExtension, String contextualHeader, RibbonDelegates delegates)
        {
            ResourceDictionary resource = null;
            if (!String.IsNullOrEmpty(xRibbonExtension.resourceuri))
            {
                resource = new ResourceDictionary
                    {
                        Source = new Uri(xRibbonExtension.resourceuri)
                    };
            }

            foreach (XRibbonTab xRibbonTab in xRibbonExtension.RibbonTab)
            {
                RibbonTab ribbonTab = new RibbonTab
                    {
                        Header = xRibbonTab.header,
                        ContextualTabGroupHeader = contextualHeader
                    };

                foreach (XRibbonGroup xRibbonGroup in xRibbonTab.RibbonGroup)
                {
                    RibbonGroup ribbonGroup = new RibbonGroup();
                    if (!String.IsNullOrEmpty(xRibbonGroup.header))
                        ribbonGroup.Header = xRibbonGroup.header;

                    foreach (XRibbonControl xRibbonControl in xRibbonGroup.Items)
                    {
                        if (xRibbonControl is XRibbonSplitButton)
                        {
                            XRibbonSplitButton xRibbonSplitButton = xRibbonControl as XRibbonSplitButton;
                            RibbonSplitButton ribbonGallery = CreateRibbonSplitButton(xRibbonSplitButton, 
                                delegates.ButtonDelegate, delegates.SelectedDelegate, delegates.UnselectedDelegate,
                                resource);
                            ribbonGroup.Items.Add(ribbonGallery);
                        }
                        else if (xRibbonControl is XRibbonMenuButton)
                        {
                            XRibbonMenuButton xRibbonMenuButton = xRibbonControl as XRibbonMenuButton;
                            RibbonMenuButton ribbonMenuButton = CreateRibbonMenuButton(xRibbonMenuButton, 
                                delegates.SelectedDelegate, delegates.UnselectedDelegate,resource);
                            ribbonGroup.Items.Add(ribbonMenuButton);
                        }
                        else if (xRibbonControl is XRibbonButton)
                        {
                            XRibbonButton xRibbonButton = xRibbonControl as XRibbonButton;
                            RibbonButton ribbonButton = CreateRibbonButton(xRibbonButton, delegates.ButtonDelegate,
                                resource);
                            ribbonGroup.Items.Add(ribbonButton);
                        }
                        else if (xRibbonControl is XRibbonCheckBox)
                        {
                            XRibbonCheckBox xRibbonCheckBox = xRibbonControl as XRibbonCheckBox;
                            RibbonCheckBox ribbonCheckBox = CreateRibbonCheckBox(xRibbonCheckBox,
                                                                                 delegates.CheckedDelegate,
                                                                                 delegates.UncheckedDelegate);
                            ribbonGroup.Items.Add(ribbonCheckBox);
                        }
                        else if (xRibbonControl is XRibbonRadioButton)
                        {
                            XRibbonRadioButton xRibbonRadioButton = xRibbonControl as XRibbonRadioButton;
                            RibbonRadioButton ribbonRadioButton = CreateRibbonRadioButton(xRibbonRadioButton,
                                                                                 delegates.CheckedDelegate,
                                                                                 delegates.UncheckedDelegate);
                            ribbonGroup.Items.Add(ribbonRadioButton);
                        }
                        else
                            throw new NotImplementedException(xRibbonControl.GetType().Name);
                        
                    }

                    ribbonTab.Items.Add(ribbonGroup);
                }

                ribbon.Items.Add(ribbonTab);
            }
        }

        private static RibbonButton CreateRibbonButton(XRibbonButton xRibbonButton, Action<String> action, ResourceDictionary resource)
        {
            RibbonButton ribbonButton = new RibbonButton
            {
                Label = xRibbonButton.header,
                ToolTipTitle = xRibbonButton.tooltipheader,
                ToolTipDescription = xRibbonButton.tooltipcontent,
                ToolTipFooterTitle = xRibbonButton.tooltipnote
            };
            ribbonButton.Click += (s, e) => action(xRibbonButton.key);

            switch (xRibbonButton.icontype)
            {
                case XRibbonIcon.None:
                    break;
                case XRibbonIcon.SmallImage:
                    if (String.IsNullOrEmpty(xRibbonButton.iconuri) && String.IsNullOrEmpty(xRibbonButton.iconresourcekey))
                        throw new PuzzlerRibbonXMLException("Missing attribute icon-uri or icon-resource-key (Small Image)!");
                    if (!String.IsNullOrEmpty(xRibbonButton.iconuri))
                    {
                        ribbonButton.SmallImageSource = new BitmapImage(new Uri(xRibbonButton.iconuri));
                    }
                    else if (!String.IsNullOrEmpty(xRibbonButton.iconresourcekey))
                    {
                        if (resource == null)
                            throw new PuzzlerRibbonXMLException("No resource-uri is given!");
                        ribbonButton.SmallImageSource = new DrawingImage((Drawing)resource[xRibbonButton.iconresourcekey]);
                    }
                    else
                        throw new NotImplementedException();
                    break;
                case XRibbonIcon.LargeImage:
                    if (String.IsNullOrEmpty(xRibbonButton.iconuri) && String.IsNullOrEmpty(xRibbonButton.iconresourcekey))
                        throw new PuzzlerRibbonXMLException("Missing attribute icon-uri or icon-resource-key (Small Image)!");
                    if (!String.IsNullOrEmpty(xRibbonButton.iconuri))
                    {
                        ribbonButton.LargeImageSource = new BitmapImage(new Uri(xRibbonButton.iconuri));
                    }
                    else if (!String.IsNullOrEmpty(xRibbonButton.iconresourcekey))
                    {
                        if (resource == null)
                            throw new PuzzlerRibbonXMLException("No resource-uri is given!");
                        ribbonButton.LargeImageSource = new DrawingImage((Drawing)resource[xRibbonButton.iconresourcekey]);
                    }
                    else
                        throw new NotImplementedException();
                    break;
                default:
                    throw new NotImplementedException(xRibbonButton.icontype.ToString());
            }

            return ribbonButton;
        }

        private static RibbonCheckBox CreateRibbonCheckBox(XRibbonCheckBox xRibbonCheckBox, Action<String> @checked, Action<String> @unchecked)
        {
            RibbonCheckBox ribbonCheckBox = new RibbonCheckBox
            {
                Label = xRibbonCheckBox.header,
                ToolTipTitle = xRibbonCheckBox.tooltipheader,
                ToolTipDescription = xRibbonCheckBox.tooltipcontent,
                ToolTipFooterTitle = xRibbonCheckBox.tooltipnote,
                IsChecked = xRibbonCheckBox.@checked
            };
            ribbonCheckBox.Checked += (s, e) => @checked(xRibbonCheckBox.key);
            ribbonCheckBox.Unchecked += (s, e) => @unchecked(xRibbonCheckBox.key);

            return ribbonCheckBox;
        }

        private static RibbonRadioButton CreateRibbonRadioButton(XRibbonRadioButton xRibbonRadioButton, Action<String> @checked, Action<String> @unchecked)
        {
            RibbonRadioButton ribbonRadioButton = new RibbonRadioButton
            {
                Label = xRibbonRadioButton.header,
                ToolTipTitle = xRibbonRadioButton.tooltipheader,
                ToolTipDescription = xRibbonRadioButton.tooltipcontent,
                ToolTipFooterTitle = xRibbonRadioButton.tooltipnote,
                IsChecked = xRibbonRadioButton.@checked
            };
            ribbonRadioButton.Checked += (s, e) => @checked(xRibbonRadioButton.key);
            ribbonRadioButton.Unchecked += (s, e) => @unchecked(xRibbonRadioButton.key);

            return ribbonRadioButton;
        }

        private static RibbonSplitButton CreateRibbonSplitButton(XRibbonSplitButton xRibbonSplitButton, Action<String> clickAction, Action<String> selectedAction, Action<String> unselectedAction, ResourceDictionary resource) {
            RibbonSplitButton ribbonSplitButton = new RibbonSplitButton
            {
                Label = xRibbonSplitButton.header,
                ToolTipTitle = xRibbonSplitButton.tooltipheader,
                ToolTipDescription = xRibbonSplitButton.tooltipcontent,
                ToolTipFooterTitle = xRibbonSplitButton.tooltipnote
            };
            ribbonSplitButton.Click += (s, e) => clickAction(xRibbonSplitButton.key);
            
            if (xRibbonSplitButton.Item != null)
            {
                RibbonGallery ribbonGallery = CreateRibbonGallery(xRibbonSplitButton.Item, selectedAction, unselectedAction, resource);
                ribbonSplitButton.Items.Add(ribbonGallery);
            }

            switch (xRibbonSplitButton.icontype)
            {
                case XRibbonIcon.None:
                    break;
                case XRibbonIcon.SmallImage:
                    if (String.IsNullOrEmpty(xRibbonSplitButton.iconuri) && String.IsNullOrEmpty(xRibbonSplitButton.iconresourcekey))
                        throw new PuzzlerRibbonXMLException("Missing attribute icon-uri or icon-resource-key (Small Image)!");
                    if (!String.IsNullOrEmpty(xRibbonSplitButton.iconuri))
                    {
                        ribbonSplitButton.SmallImageSource = new BitmapImage(new Uri(xRibbonSplitButton.iconuri));
                    }
                    else if (!String.IsNullOrEmpty(xRibbonSplitButton.iconresourcekey))
                    {
                        if (resource == null)
                            throw new PuzzlerRibbonXMLException("No resource-uri is given!");
                        ribbonSplitButton.SmallImageSource = new DrawingImage((Drawing)resource[xRibbonSplitButton.iconresourcekey]);
                    }
                    else
                        throw new NotImplementedException();
                    break;
                case XRibbonIcon.LargeImage:
                    if (String.IsNullOrEmpty(xRibbonSplitButton.iconuri) && String.IsNullOrEmpty(xRibbonSplitButton.iconresourcekey))
                        throw new PuzzlerRibbonXMLException("Missing attribute icon-uri or icon-resource-key (Small Image)!");
                    if (!String.IsNullOrEmpty(xRibbonSplitButton.iconuri))
                    {
                        ribbonSplitButton.LargeImageSource = new BitmapImage(new Uri(xRibbonSplitButton.iconuri));
                    }
                    else if (!String.IsNullOrEmpty(xRibbonSplitButton.iconresourcekey))
                    {
                        if (resource == null)
                            throw new PuzzlerRibbonXMLException("No resource-uri is given!");
                        ribbonSplitButton.LargeImageSource = new DrawingImage((Drawing)resource[xRibbonSplitButton.iconresourcekey]);
                    }
                    else
                        throw new NotImplementedException();
                    break;
                default:
                    throw new NotImplementedException(xRibbonSplitButton.icontype.ToString());
            }

            return ribbonSplitButton;
        }

        private static RibbonMenuButton CreateRibbonMenuButton(XRibbonMenuButton xRibbonMenuButton, Action<String> selectedAction, Action<String> unselectedAction, ResourceDictionary resource)
        {
            RibbonMenuButton ribbonMenuButton = new RibbonMenuButton
            {
                Label = xRibbonMenuButton.header,
                ToolTipTitle = xRibbonMenuButton.tooltipheader,
                ToolTipDescription = xRibbonMenuButton.tooltipcontent,
                ToolTipFooterTitle = xRibbonMenuButton.tooltipnote
            };

            if (xRibbonMenuButton.Item != null)
            {
                RibbonGallery ribbonGallery = CreateRibbonGallery(xRibbonMenuButton.Item, selectedAction, unselectedAction, resource);
                ribbonMenuButton.Items.Add(ribbonGallery);
            }

            switch (xRibbonMenuButton.icontype)
            {
                case XRibbonIcon.None:
                    break;
                case XRibbonIcon.SmallImage:
                    if (String.IsNullOrEmpty(xRibbonMenuButton.iconuri) && String.IsNullOrEmpty(xRibbonMenuButton.iconresourcekey))
                        throw new PuzzlerRibbonXMLException("Missing attribute icon-uri or icon-resource-key (Small Image)!");
                    if (!String.IsNullOrEmpty(xRibbonMenuButton.iconuri))
                    {
                        ribbonMenuButton.SmallImageSource = new BitmapImage(new Uri(xRibbonMenuButton.iconuri));
                    }
                    else if (!String.IsNullOrEmpty(xRibbonMenuButton.iconresourcekey))
                    {
                        if (resource == null)
                            throw new PuzzlerRibbonXMLException("No resource-uri is given!");
                        ribbonMenuButton.SmallImageSource = new DrawingImage((Drawing)resource[xRibbonMenuButton.iconresourcekey]);
                    }
                    else
                        throw new NotImplementedException();
                    break;
                case XRibbonIcon.LargeImage:
                    if (String.IsNullOrEmpty(xRibbonMenuButton.iconuri) && String.IsNullOrEmpty(xRibbonMenuButton.iconresourcekey))
                        throw new PuzzlerRibbonXMLException("Missing attribute icon-uri or icon-resource-key (Small Image)!");
                    if (!String.IsNullOrEmpty(xRibbonMenuButton.iconuri))
                    {
                        ribbonMenuButton.LargeImageSource = new BitmapImage(new Uri(xRibbonMenuButton.iconuri));
                    }
                    else if (!String.IsNullOrEmpty(xRibbonMenuButton.iconresourcekey))
                    {
                        if (resource == null)
                            throw new PuzzlerRibbonXMLException("No resource-uri is given!");
                        ribbonMenuButton.LargeImageSource = new DrawingImage((Drawing)resource[xRibbonMenuButton.iconresourcekey]);
                    }
                    else
                        throw new NotImplementedException();
                    break;
                default:
                    throw new NotImplementedException(xRibbonMenuButton.icontype.ToString());
            }

            return ribbonMenuButton;
        }

        #region Gallery

        private static RibbonGallery CreateRibbonGallery(XRibbonGallery xRibbonGallery, Action<String> selectedAction, Action<String> unselectedAction, ResourceDictionary resource)
        {
            RibbonGallery ribbonGallery = new RibbonGallery
                {
                    MinColumnCount = xRibbonGallery.columncount,
                    MaxColumnCount = xRibbonGallery.columncount
                };
            foreach (var item in xRibbonGallery.Items)
            {
                if (item is XRibbonGalleryCategory)
                {
                    XRibbonGalleryCategory xRibbonGalleryCategory = item as XRibbonGalleryCategory;
                    RibbonGalleryCategory ribbonGalleryCategory = InsertRibbonGalleryCategory(xRibbonGalleryCategory,
                                                                                              selectedAction,
                                                                                              unselectedAction, resource);
                    ribbonGallery.Items.Add(ribbonGalleryCategory);
                }
                else if (item is XRibbonGalleryIcon)
                {
                    XRibbonGalleryIcon xRibbonGalleryIcon = item as XRibbonGalleryIcon;
                    RibbonGalleryItem ribbonGalleryIcon = InsertRibbonGalleryIcon(xRibbonGalleryIcon, selectedAction,
                                                                                  unselectedAction, resource);
                    ribbonGallery.Items.Add(ribbonGalleryIcon);
                }
                else
                    throw new NotImplementedException(item.GetType().Name);
            }

            return ribbonGallery;
        }

        private static RibbonGalleryCategory InsertRibbonGalleryCategory(XRibbonGalleryCategory xRibbonGalleryCategory, Action<String> selectedAction, Action<String> unselectedAction, ResourceDictionary resource)
        {
            RibbonGalleryCategory ribbonGalleryCategory = new RibbonGalleryCategory
                {
                    Header = xRibbonGalleryCategory.header
                };
            foreach (XRibbonGalleryIcon xRibbonGalleryIcon in xRibbonGalleryCategory.RibbonGalleryIcon)
            {
                RibbonGalleryItem ribbonGalleryIcon = InsertRibbonGalleryIcon(xRibbonGalleryIcon, selectedAction,
                                                                              unselectedAction, resource);
                ribbonGalleryCategory.Items.Add(ribbonGalleryIcon);
            }

            return ribbonGalleryCategory;
        }

        private static RibbonGalleryItem InsertRibbonGalleryIcon(XRibbonGalleryIcon xRibbonGalleryIcon, Action<String> selectedAction, Action<String> unselectedAction, ResourceDictionary resource)
        {
            Image image = new Image();
            if (!String.IsNullOrEmpty(xRibbonGalleryIcon.iconuri))
            {
                image.Source = new BitmapImage(new Uri(xRibbonGalleryIcon.iconuri));
            }
            else if (!String.IsNullOrEmpty(xRibbonGalleryIcon.iconresourcekey))
            {
                if (resource == null)
                    throw new PuzzlerRibbonXMLException("No resource-uri is given!");
                image.Source = new DrawingImage((Drawing)resource[xRibbonGalleryIcon.iconresourcekey]);
            }
            else
                throw new NotImplementedException();

            RibbonGalleryItem ribbonGalleryItem = new RibbonGalleryItem
                {
                    Content = image,
                    ToolTipTitle = xRibbonGalleryIcon.tooltipheader,
                    ToolTipDescription = xRibbonGalleryIcon.tooltipcontent,
                    ToolTipFooterTitle = xRibbonGalleryIcon.tooltipnote,
                };
            ribbonGalleryItem.Selected += (s, e) => selectedAction(xRibbonGalleryIcon.key);
            ribbonGalleryItem.Unselected += (s, e) => unselectedAction(xRibbonGalleryIcon.key);

            return ribbonGalleryItem;
        }

        #endregion
    }
}
